package utils

import (
	"bufio"
	"certificate-manager/pkg/constant"
	"certificate-manager/pkg/log"
	"go.uber.org/zap"
	os "os"
)

// Exists 判断文件/文件夹是否存在
func Exists(path string) bool {
	//os.Stat获取文件信息
	_, err := os.Stat(path)

	if os.IsNotExist(err) {
		return false
	}

	return true
}

// CreatePath 创建文件夹
func CreatePath(path string) bool {
	err := os.Mkdir(path, os.ModePerm)

	if err != nil {
		return false
	}

	return true
}

func WriteCertificate(key string, cert []byte) error {
	dir, err := os.Getwd()
	if err != nil {
		log.Logger.Error("【Write Certificate】os.Getwd() error.", zap.Any("err", err))
		return err
	}
	//1、判断目标文件夹是否存在
	targetPath := dir + constant.DefaultCertificateStorePath + key
	pathExisted := Exists(targetPath)

	if !pathExisted {
		log.Logger.Info("【Write Certificate】path is not exist.", zap.String("path", targetPath))
		//2、创建文件夹
		err := os.MkdirAll(targetPath, os.ModePerm)
		if err != nil {
			log.Logger.Error("【Write Certificate】mkdir path error.", zap.Any("err", err))
			return err
		}
	}

	//3、判断证书文件是否存在
	var targetCertificateFile *os.File

	targetCertificateFileName := targetPath + "/" + constant.CertificateFileName
	certificateExisted := Exists(targetCertificateFileName)
	if !certificateExisted {
		log.Logger.Info("【Write Certificate】certificate file is not exist.", zap.String("key", key))
		//4、创建文件
		file, err := os.Create(targetCertificateFileName)
		if err != nil {
			log.Logger.Error("【Write Certificate】create certificate file error.", zap.Any("key", key), zap.Any("err", err))
			return err
		}
		targetCertificateFile = file
	}

	//5、关闭文件
	defer func() {
		err := targetCertificateFile.Close()
		if err != nil {
			return
		}
	}()

	//6、写入文件，使用带缓存的 *Writer
	certificateWrite := bufio.NewWriter(targetCertificateFile)
	_, err = certificateWrite.WriteString(string(cert))
	if err != nil {
		log.Logger.Error("【Write Certificate】write file error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	//7、Flush将缓存的文件真正写入到文件中
	err = certificateWrite.Flush()
	if err != nil {
		log.Logger.Error("【Write Certificate】flush file error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	return nil
}

func WritePrivateKey(key string, privateKey []byte) error {
	dir, err := os.Getwd()
	if err != nil {
		log.Logger.Error("【Write Certificate】os.Getwd() error.", zap.Any("err", err))
		return err
	}

	//1、判断目标文件夹是否存在
	targetPath := dir + constant.DefaultCertificateStorePath + key
	pathExisted := Exists(targetPath)

	if !pathExisted {
		log.Logger.Info("【Write PrivateKey】path is not exist.", zap.String("path", targetPath))
		//2、创建文件夹
		err := os.MkdirAll(targetPath, os.ModePerm)
		if err != nil {
			log.Logger.Error("【Write PrivateKey】mkdir path error.", zap.Any("err", err))
			return err
		}
	}

	//3、判断私钥文件是否存在
	var targetPrivateKeyFile *os.File

	targetPrivateKeyFileName := targetPath + "/" + constant.PrivateKeyFileName
	certificateExisted := Exists(targetPrivateKeyFileName)
	if !certificateExisted {
		log.Logger.Info("【Write PrivateKey】certificate file is not exist.", zap.String("key", key))
		//4、创建文件
		file, err := os.Create(targetPrivateKeyFileName)
		if err != nil {
			log.Logger.Error("【Write PrivateKey】create certificate file error.", zap.Any("key", key), zap.Any("err", err))
			return err
		}
		targetPrivateKeyFile = file
	}

	//5、关闭文件
	defer func() {
		err := targetPrivateKeyFile.Close()
		if err != nil {
			return
		}
	}()

	//6、写入文件，使用带缓存的 *Writer
	privateKeyWrite := bufio.NewWriter(targetPrivateKeyFile)
	_, err = privateKeyWrite.WriteString(string(privateKey))
	if err != nil {
		log.Logger.Error("【Write PrivateKey】write file error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	//7、Flush将缓存的文件真正写入到文件中
	err = privateKeyWrite.Flush()
	if err != nil {
		log.Logger.Error("【Write PrivateKey】flush file error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	return nil
}

// WriteCertificateAndPrivateKey 写入证书及私钥
func WriteCertificateAndPrivateKey(key string, cert, privateKey []byte) error {
	//1、写入证书
	err := WriteCertificate(key, cert)
	if err != nil {
		log.Logger.Error("【Write Certificate And PrivateKey】write certificate error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	//2、写入私钥
	err = WritePrivateKey(key, privateKey)
	if err != nil {
		log.Logger.Error("【Write Certificate And PrivateKey】write privateKey error.", zap.Any("key", key), zap.Any("err", err))
		return err
	}

	return nil
}
